package exec

import (
	"io"
	// "os"
	"os/exec"
)

// "xz", "--compress", "--stdout"
// "ping", "-c", "4", "127.0.0.1"
// "/bin/sh", "-c", "ping -c 4 127.0.0.1"

// file, err := exec.LookPath("notepad")

// var out bytes.Buffer
// cmd.Stdout = &out
// cmd.Stdout = os.Stdout

// cmd.Stdin = strings.NewReader("some input")
// stdin, err := cmd.StdinPipe()
// _, err = stdin.Write([]byte("test"))
// stdin.Close()

// stdout, err := cmd.StdoutPipe()
// content, err := ioutil.ReadAll(stdout)

// Exec("/bin/sh", "-c", "ping -c 4 127.0.0.1")
func Exec(name string, args ...string) (string, error) {
	cmd := exec.Command(name, args...)

	output, err := cmd.Output() // []uint8
	// output, err := cmd.CombinedOutput() // []uint8 把标准错误和标准
	if err != nil {
		return "", err
	}

	return string(output), nil
}

// ExecPipe1(func(output string){
//     fmt.Print(output)
// }, "/bin/sh", "-c", "ping -c 4 127.0.0.1")
func ExecPipe1(outputCallback func(string), name string, args ...string) error {
	cmd := exec.Command(name, args...)

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}

	cmd.Stderr = cmd.Stdout

	if err = cmd.Start(); err != nil {
		return err
	}

	for {
		tmp := make([]byte, 1024)

		_, err := stdout.Read(tmp)
		if err != nil {
			break
		}

		outputCallback(string(tmp))
	}

	if err = cmd.Wait(); err != nil {
		return err
	}

	return nil
}

// reader := ExecPipe2("/bin/sh", "-c", "ping -c 4 127.0.0.1")
// buf := new(bytes.Buffer)
// buf.ReadFrom(reader)
// buf.String()
func ExecPipe2(name string, args ...string) io.ReadCloser {
	cmd := exec.Command(name, args...)

	pipeRead, pipeWrite := io.Pipe()
	cmd.Stdout = pipeWrite

	go func() {
		err := cmd.Run()
		pipeWrite.CloseWithError(err)
	}()

	return pipeRead
}

//func ExecPipe3(name string, args ...string) {
//	cmd := exec.Command(name, args...)
//
//    stdout, err := cmd.StdoutPipe()
//    if err != nil {
//        return err
//    }
//
//    stderr, err := cmd.StderrPipe()
//    if err != nil {
//        return err
//    }
//
//    if err := cmd.Start(); err != nil {
//        return err
//    }
//
//    bytesErr, err := ioutil.ReadAll(stderr)
//    if err != nil {
//        return err
//    }
//
//    if len(bytesErr) != 0 {
//        return bytesErr
//    }
//
//    bytes, err := ioutil.ReadAll(stdout)
//    if err != nil {
//        return err
//    }
//
//    if err := cmd.Wait(); err != nil {
//        return err
//    }
//
//    return bytes
//}
